package stringutil

import (
	"fmt"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"unicode"
	"unsafe"
)

// 清理map中字符串类型数据的前后空格
func TrimAttribute(data map[string]interface{}) {
	if data == nil {
		return
	}

	for k, v := range data {
		if _, ok := v.(string); ok {
			data[k] = strings.TrimSpace(v.(string))
		}
	}
}

// 清除前后空格
func Trim(str string) string {
	return strings.TrimSpace(str)
}

// 转换字符串
func ToStr(data interface{}) string {
	if data == nil {
		return ""
	}

	switch obj := data.(type) {
	case []uint8:
		return Byte2Str(obj)
	default:
		return fmt.Sprintf("%v", obj)
	}
}

// 字符串拼接
func Append(data ...interface{}) string {
	if len(data) < 1 {
		return ""
	}

	var build strings.Builder
	for i := 0; i < len(data); i++ {
		if nil == data[i] {
			continue
		}

		switch obj := data[i].(type) {
		case []uint8:
			build.WriteString(Byte2Str(obj))
		default:
			build.WriteString(fmt.Sprintf("%v", obj))
		}
	}

	return build.String()
}

// 判断是否以特定字符结尾
func HasEnd(str, end string) bool {
	return strings.HasSuffix(str, end)
}

// 判断是否以特定字符开头
func HasStart(str, start string) bool {
	return strings.HasPrefix(str, start)
}

// FirstUpper 字符串首字母大写
func FirstUpper(s string) string {
	if s == "" {
		return ""
	}

	return strings.ToUpper(s[:1]) + s[1:]
}

// FirstLower 字符串首字母小写
func FirstLower(s string) string {
	if s == "" {
		return ""
	}

	return strings.ToLower(s[:1]) + s[1:]
}

// 判断是否包含子串
func Has(source, str string) bool {
	return strings.Contains(source, str)
}

// 将字符串大写
func Upper(str string) string {
	return strings.ToUpper(str)
}

// 将字符串小写
func Lower(str string) string {
	return strings.ToLower(str)
}

/**
 * 截取指定字符串间的内容
 * @param source 源
 * @param beginStr 开始字符串
 * @param endStr 结束字符串
 * @param lastIndexOf 是否从后面开始去截取字符串
 * @return
 */
func SubBetween(source, beginStr, endStr string, lastIndexOf bool) string {
	if source == "" { //源串为空
		return ""
	}

	if (beginStr == "") || (endStr == "") { //开始符没定义
		return ""
	}

	if endStr == "" { //结束符没定义
		return ""
	}

	iSt := strings.Index(source, beginStr) //开始位置

	if iSt < 0 { //起始字符不存在
		return ""
	}

	tmp := source[iSt+1:]

	iEd := -1
	if lastIndexOf {
		iEd = strings.LastIndex(tmp, endStr) //结束位置(从后面开始取)
	} else {
		iEd = strings.Index(tmp, endStr)
	}

	if iEd < 0 { //结束字符不存在
		return ""
	}

	result := tmp[:iEd]

	return result
}

/**
 * 移除指定字符串间的内容(仅一次)，并返回新值
 * @param source 源
 * @param beginStr 开始字符串
 * @param endStr 结束字符串
 * @param lastIndexOf 是否从后面开始去截取字符串
 * @return
 */
func RemoveBetween(source, beginStr, endStr string, lastIndexOf bool) string {
	if source == "" { //源串为空
		return source
	}

	if (beginStr == "") || (endStr == "") { //开始符没定义
		return source
	}

	if endStr == "" { //结束符没定义
		return source
	}

	iSt := strings.Index(source, beginStr) //开始位置

	if iSt < 0 { //起始字符不存在
		return source
	}

	temp := source[iSt+len(beginStr):]

	iEd := -1
	if lastIndexOf {
		iEd = strings.LastIndex(temp, endStr) //结束位置(从后面开始取)
	} else {
		iEd = strings.Index(temp, endStr)
	}

	if iEd < 0 { //结束字符不存在
		return source
	}

	var sb strings.Builder
	sb.WriteString(source[:iSt])
	sb.WriteString(temp[iEd+len(endStr):])

	return sb.String()
}

/**
 * 替换指定字符串间的内容(仅一次)，并返回新值
 * @param source 源
 * @param beginStr 开始字符串
 * @param endStr 结束字符串
 * @param newStr 新字符串
 * @param lastIndexOf 是否从后面开始去截取字符串
 * @return
 */
func ChangeBetween(source, beginStr, endStr, newStr string, lastIndexOf bool) string {
	if source == "" { //源串为空
		return source
	}

	if (beginStr == "") || (endStr == "") { //开始符没定义
		return source
	}

	if endStr == "" { //结束符没定义
		return source
	}

	iSt := strings.Index(source, beginStr) //开始位置

	if iSt < 0 { //起始字符不存在
		return source
	}

	temp := source[iSt+len(beginStr):]

	iEd := -1
	if lastIndexOf {
		iEd = strings.LastIndex(temp, endStr) //结束位置(从后面开始取)
	} else {
		iEd = strings.Index(temp, endStr)
	}

	if iEd < 0 { //结束字符不存在
		return source
	}

	var sb strings.Builder
	sb.WriteString(source[:iSt])
	sb.WriteString(newStr)
	sb.WriteString(temp[iEd+len(endStr):])

	return sb.String()
}

/**
 * 截取字符串
 * @param source 源字符串
 * @param beginIndex 开始位置 0开始
 * @param endMaxIndex 最大结束位置,超出则取字符串最大位置
 * @return
 */
func SubMaxStr(source string, beginIndex, endMaxIndex int) string {
	if source == "" {
		return ""
	}

	if beginIndex < 0 {
		beginIndex = 0
	}

	vSource := []rune(source)

	if beginIndex >= endMaxIndex || beginIndex >= len(vSource) {
		return ""
	}

	if endMaxIndex >= len(vSource) {
		return string(vSource[beginIndex:])
	}

	return string(vSource[beginIndex:endMaxIndex])
}

/**
 * 是否包含中文,含中文返回true
 * @param str
 * @return
 */
func IsCompriseChineseChar(str string) bool {
	if str == "" {
		return false
	}

	var a = regexp.MustCompile("^[\u4e00-\u9fa5]$")

	for _, v := range str { //golang中string的底层是byte类型，所以单纯的for输出中文会出现乱码，这里选择for-range来输出
		if a.MatchString(string(v)) {
			return true
		}
	}

	return false
}

/**
 * 是否全中文,全中文返回true
 * @param str
 * @return
 */
func IsAllChineseChar(str string) bool {
	if str == "" {
		return false
	}

	var a = regexp.MustCompile("^[\u4e00-\u9fa5]$")

	for _, v := range str { //golang中string的底层是byte类型，所以单纯的for输出中文会出现乱码，这里选择for-range来输出
		if !a.MatchString(string(v)) {
			return false
		}
	}

	return true
}

/**
 * 判断是否存在字符串
 * @param str
 * @return
 */
func HasStr(data interface{}, str string) bool {
	typeName := reflect.TypeOf(data).String()

	if typeName == "string" {
		return strings.Contains(data.(string), str)
	}

	if typeName == "[]string" {
		for _, v := range data.([]string) {
			if v == str {
				return true
			}
		}

		return false
	}

	if typeName == "map[string]string" {
		for _, v := range data.(map[string]string) {
			if v == str {
				return true
			}
		}

		return false
	}

	if typeName == "map[string]interface {}" {
		for k := range data.(map[string]interface{}) {
			if k == str {
				return true
			}
		}

		return false
	}

	// if strigns.HasPrefix(typeName, "map[string]inter") {

	// }

	// switch {
	// case "string":
	// 	return strings.Contains(data.(string), str)
	// cases "[]"
	// }

	return false
}

/**
 * 彻底替换指定内容
 * @param source
 * @param old
 * @param new
 * @return
 */
func ReplaceAll(source, old, new string) string {
	result := source

	for {
		if !strings.Contains(result, old) {
			break
		}

		result = strings.Replace(result, old, new, -1)
	}

	return result
}

/**
 * 彻底替换指定内容
 * @param formatLong
 * @param data
 * @return
 */
func SupplyZero(formatLong int, data interface{}) string {
	str := fmt.Sprintf("%v", data)
	iLen := len(str)
	i2 := formatLong - iLen

	if i2 < 1 {
		return str
	}

	sSt := fmt.Sprintf("%0"+strconv.Itoa(i2)+"d", 0)

	return sSt + str
}

/**
 * 彻底替换指定内容
 * @param source 源字符串
 * @param sub 待删除子字符串
 * @return
 */
func DelStr(source string, sub ...string) string {
	result := source

	for _, val := range sub {
		for {
			if !strings.Contains(result, val) {
				break
			}

			result = strings.Replace(result, val, "", -1)
		}
	}

	return result
}

// Byte转Str
func Byte2Str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// 是否小写开头
func IsLowerStart(s string) bool {
	if len(s) == 0 {
		return false // 空字符串不被视为以小写字母开头
	}

	runeValue := rune(s[0])
	return unicode.IsLower(runeValue)
}

// 是否大写开头
func IsUpperStart(s string) bool {
	if len(s) == 0 {
		return false // 空字符串不被视为以大写字母开头
	}

	runeValue := rune(s[0])
	return unicode.IsUpper(runeValue)
}
